#ifndef __WIZ_BNF_PARSER_INTEGER_IMPL_HPP__SHANHAOBO_19800429__
#define __WIZ_BNF_PARSER_INTEGER_IMPL_HPP__SHANHAOBO_19800429__

#include "./WizBNFParserSign.hpp"
#include <limits>

using namespace Wiz;
namespace Wiz
{
    namespace BNF
    {
        namespace Parser
        {
            namespace Impl
            {
                namespace Accumulate
                {
                    template <typename T, int Radix>
                    struct Positive
                    {
                        //  Use this accumulator if number is positive
                        static ::Wiz::Bool::Type AddDigit(T& n, T digit)
                        {
                            if (std::numeric_limits<T>::is_specialized)
                            {
                                static T const max = (std::numeric_limits<T>::max)();
                                static T const max_div_radix = max/Radix;

                                if (n > max_div_radix)
                                {
                                    return ::Wiz::Bool::False;
                                }
                                n *= Radix;

                                if (n > max - digit)
                                {
                                    return ::Wiz::Bool::False;
                                }
                                n += digit;

                                return ::Wiz::Bool::True;
                            }

                            n *= Radix;
                            n += digit;

                            return ::Wiz::Bool::True;
                        }
                    };

                    template <typename T, int Radix>
                    struct Negative
                    {
                        //  Use this accumulator if number is negative
                        static ::Wiz::Bool::Type AddDigit(T& n, T digit)
                        {
                            if (std::numeric_limits<T>::is_specialized)
                            {
                                typedef std::numeric_limits<T> num_limits;
                                static T const min =
                                    (!num_limits::is_integer && num_limits::is_signed && num_limits::has_denorm) ?
                                    -(num_limits::max)() : (num_limits::min)();
                                static T const min_div_radix = min/Radix;

                                if (n < min_div_radix)
                                {
                                    return ::Wiz::Bool::False;
                                }
                                n *= Radix;

                                if (n < min + digit)
                                {
                                    return ::Wiz::Bool::False;
                                }
                                n -= digit;

                                return ::Wiz::Bool::True;
                            }

                            n *= Radix;
                            n += digit;

                            return ::Wiz::Bool::True;
                        }
                    };
                } /// namespace Accumulate

                namespace Integer
                {
                    template <int MaxDigits>
                    inline ::Wiz::Bool::Type AllowMoreDigits(::Wiz::Size::In i)
                    {
                        return i < MaxDigits;
                    }

                    template <>
                    inline ::Wiz::Bool::Type AllowMoreDigits<-1>(::Wiz::Size::In)
                    {
                        return ::Wiz::Bool::True;
                    }

                    //////////////////////////////////
                    template <
                        int Radix, unsigned MinDigits, int MaxDigits,
                        typename AccumulateT
                    >
                    struct Extract
                    {
                        typedef AccumulateT                     tAccumulate;
                        template<typename ScannerT, typename ElementT>
                        static ::Wiz::Bool::Type DoParse(ScannerT& Scan, ElementT& N, ::Wiz::Size::InOut Cnt)
                        {
                            ::Wiz::Size::Type i = 0;
                            ElementT Digit;
                            while((Scan.AtEnd() == ::Wiz::Bool::False)  && 
                                ::Wiz::BNF::Parser::Impl::Integer::AllowMoreDigits<MaxDigits>(i)           && 
                                ::Wiz::RadixTraits::Type<Radix>::IsDigit(Digit, *Scan)
                                )
                            {
                                if (tAccumulate::AddDigit(N, Digit) == ::Wiz::Bool::False)
                                {
                                    return ::Wiz::Bool::False;
                                }
                                ++i, ++Scan, ++Cnt;
                            }
                            return i >= MinDigits;
                        }
                    };

                    namespace Signal
                    {
                        template <typename ElementT, int Radix, unsigned MinDigits, int MaxDigits>
                        struct Type : public ::Wiz::BNF::Parser::Type<Type<ElementT, Radix, MinDigits, MaxDigits>>
                        {
                            typedef Type            tThis;
                            typedef ElementT        tElement;

                            template <typename ScannerT>
                            struct Result
                            {
                                typedef typename ::Wiz::BNF::Match::Result<
                                    ScannerT,
                                    tElement
                                >::tType tType;
                            };

                            template <typename ScannerT>
                            typename ::Wiz::BNF::Parser::Result<tThis, ScannerT>::tType
                                ParseImpl(ScannerT const& Scan) const
                            {
                                typedef ::Wiz::BNF::Parser::Impl::Integer::Extract<Radix, MinDigits, MaxDigits,
                                    Accumulate::Negative<tElement, Radix> > tExtractNegative;
                                typedef ::Wiz::BNF::Parser::Impl::Integer::Extract<Radix, MinDigits, MaxDigits,
                                    Accumulate::Positive<tElement, Radix> > tExtractPositive;

                                typedef typename ScannerT::tIterator                        tIterator;
                                if (Scan.AtEnd() == ::Wiz::Bool::False)
                                {
                                    tElement n = 0;
                                    ::Wiz::Size::Type Cnt = 0;
                                    tIterator StartItr = Scan.m_Curr;

                                    ::Wiz::Bool::Type Hit;

                                    if (::Wiz::BNF::Parser::Sign::DoParse(Cnt, Scan))
                                    {
                                        Hit = tExtractNegative::DoParse(Scan, n, Cnt);
                                    }
                                    else
                                    {
                                        Hit = tExtractPositive::DoParse(Scan, n, Cnt);
                                    }

                                    if (Hit)
                                    {
                                        return Scan.CreateMatch(Cnt, n, StartItr, Scan.m_Curr);
                                    }
                                }
                                return Scan.NoMatch();
                            }
                        };
                    } /// end of namespace Signal

                    namespace Unsignal
                    {
                        template <typename ElementT, int Radix, unsigned MinDigits, int MaxDigits>
                        struct Type : public ::Wiz::BNF::Parser::Type<Type<ElementT, Radix, MinDigits, MaxDigits>>
                        {
                            typedef Type            tThis;
                            typedef ElementT        tElement;

                            template <typename ScannerT>
                            struct Result
                            {
                                typedef typename ::Wiz::BNF::Match::Result<
                                    ScannerT,
                                    tElement
                                >::tType tType;
                            };

                            template <typename ScannerT>
                            typename ::Wiz::BNF::Parser::Result<tThis, ScannerT>::tType
                                ParseImpl(ScannerT const& Scan) const
                            {
                                typedef ::Wiz::BNF::Parser::Impl::Integer::Extract<Radix, MinDigits, MaxDigits,
                                    Accumulate::Positive<tElement, Radix> > tExtractPositive;

                                typedef typename ScannerT::tIterator        tIterator;
                                if (Scan.AtEnd() == ::Wiz::Bool::False)
                                {
                                    tElement n = 0;
                                    ::Wiz::Size::Type Cnt = 0;
                                    tIterator StartItr = Scan.m_Curr;

                                    if (tExtractPositive::DoParse(Scan, n, Cnt))
                                    {
                                        return Scan.CreateMatch(Cnt, n, StartItr, Scan.m_Curr);
                                    }
                                }
                                return Scan.NoMatch();
                            }
                        };
                    } /// end of namespace Unsignal
                } /// end of namespace Integer
            } /// end of namespace Impl
        } /// end of namespace Parser
    } /// end of namespace BNF
} /// end of namespace Wiz

#endif /*__WIZ_BNF_PARSER_INTEGER_IMPL_HPP__SHANHAOBO_19800429__*/
